package com.kk.xhr.model.service.impl;

import com.kk.xhr.common.pojo.TrainStatusEnum;
import com.kk.xhr.model.assembler.TrainStructKit;
import com.kk.xhr.model.dao.EmployeeTrainDynamicSqlSupport;
import com.kk.xhr.model.dao.EmployeeTrainMapper;
import com.kk.xhr.model.dto.PageDto;
import com.kk.xhr.model.dto.TrainDTO;
import com.kk.xhr.model.dto.TrainQueryRequestDTO;
import com.kk.xhr.model.entity.EmployeeTrain;
import com.kk.xhr.model.service.ITrainService;
import lombok.RequiredArgsConstructor;
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;

/**
 * @author kkmystery
 * @version 1.0 2021/3/31
 * @since 1.0.0
 */
@Repository
@RequiredArgsConstructor
public class TrainServiceImpl implements ITrainService {
    private final EmployeeTrainMapper trainMapper;
    private final TrainStructKit instance = TrainStructKit.INSTANCE;

    /**
     * {@inheritDoc}
     */
    @Override
    public PageDto<TrainDTO> queryPage(TrainQueryRequestDTO dto) {
        long count = trainMapper.count(dsl -> applyQueryArgs(dsl.where(), dto));
        if (0 == count) {
            return PageDto.empty();
        }
        return new PageDto<>(count, trainMapper.select(dsl -> applyQueryArgs(dsl.where(), dto)
            .orderBy(EmployeeTrainDynamicSqlSupport.id.descending())
            .limit(dto.getLimit())
            .offset(dto.getOffset()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList()));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<TrainDTO> query(Long userId) {
        return trainMapper.select(dsl ->
            dsl.where(EmployeeTrainDynamicSqlSupport.userId, isEqualTo(userId))
            .orderBy(EmployeeTrainDynamicSqlSupport.status, EmployeeTrainDynamicSqlSupport.id.descending()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchAdd(Collection<TrainDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        List<EmployeeTrain> trainList = list.stream()
            .distinct()
            .map(instance::toEntity)
            .collect(Collectors.toList());
        MultiRowInsertStatementProvider<EmployeeTrain> provider = insertMultiple(trainList)
            .into(EmployeeTrainDynamicSqlSupport.employeeTrain)
            .map(EmployeeTrainDynamicSqlSupport.userId).toProperty("userId")
            .map(EmployeeTrainDynamicSqlSupport.trainDate).toProperty("trainDate")
            .map(EmployeeTrainDynamicSqlSupport.content).toProperty("content")
            .map(EmployeeTrainDynamicSqlSupport.remark).toProperty("remark")
            .map(EmployeeTrainDynamicSqlSupport.status).toProperty("status")
            .build().render(RenderingStrategies.MYBATIS3);
        return list.size() == trainMapper.insertMultiple(provider);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean modify(Long id, TrainDTO dto) {
        EmployeeTrain entity = instance.toEntity(dto).withId(id);
        return 1 == trainMapper.updateByPrimaryKeySelective(entity);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void modifyStatus(Long id, TrainStatusEnum status) {
        if (null == status) {
            return;
        }
        trainMapper.updateByPrimaryKeySelective(new EmployeeTrain().withId(id).withStatus(status.getValue()));
    }

    private <T extends AbstractWhereDSL<T>> T applyQueryArgs(T where, TrainQueryRequestDTO dto) {
        where.and(EmployeeTrainDynamicSqlSupport.userId, isEqualToWhenPresent(dto.getUserId()));
        if (null != dto.getStatus()) {
            where.and(EmployeeTrainDynamicSqlSupport.status, isEqualTo(dto.getStatus().getValue()));
        }
        return where;
    }
}
